﻿using LuaInterface;

namespace Framework
{
    [LuaInterface.NoToLua]
    public sealed class GeneralCallBack : SLICacheable
    {
        private static readonly SLObjectPool<GeneralCallBack> CbPool = new SLObjectPool<GeneralCallBack>(256);

        public static GeneralCallBack Get(System.Action csharpCb, LuaFunction luaCb, LuaTable luaObj)
        {
            var ret = CbPool.GetObject();
            ret.Reuse(csharpCb, luaCb, luaObj);
            return ret;
        }

        public static GeneralCallBack Get(System.Action csharpCb)
        {
            var ret = CbPool.GetObject();
            ret.Reuse(csharpCb, null, null);
            return ret;
        }

        public static void Invoke(ref GeneralCallBack gcb, params object[] args)
        {
            if (null != gcb)
            {
                if (args == null || 0 == args.Length)
                {
                    gcb.DoCallBack();
                    return;
                }
                gcb.DoLuaCallBackWithArgs(args);
            }
        }

        public static void InvokeAndRecycle(ref GeneralCallBack gcb, params object[] args)
        {
            if (null != gcb)
            {
                Invoke(ref gcb, args);
                RecycleInst(ref gcb);
            }
        }

        public static void GetOrReUse(ref GeneralCallBack gcb, LuaFunction luaCb, LuaTable luaObj)
        {
            if (null == gcb)
            {
                gcb = CbPool.GetObject();
            }

            gcb.Reuse(null, luaCb, luaObj);
        }

        public static void GetOrReUse(ref GeneralCallBack gcb, System.Action csharpCb)
        {
            if (null == gcb)
            {
                gcb = CbPool.GetObject();
            }

            gcb.Reuse(csharpCb, null, null);
        }
        
        public static void RecycleInst(ref GeneralCallBack callBack)
        {
            if (null == callBack)
            {
                return;
            }
            CbPool.PutObject(callBack);
            callBack = null;
        }

        public static void Clear()
        {
            Logger.Log("GeneralCallBack.Clear(), CbPool count = " + CbPool.CurCount);
            CbPool.Clear();
        }

        private System.Action _csharpCb;
        private LuaFunction _luaCb;
        private LuaTable _luaObj;

        /// <summary>
        /// 重设这个通用回调里面参数，用来重用
        /// </summary>
        /// <param name="csharpCb">没有传null</param>
        /// <param name="luaCb">没有传null</param>
        /// <param name="luaObj">没有传null</param>
        private void Reuse(System.Action csharpCb, LuaFunction luaCb, LuaTable luaObj)
        {
            this._csharpCb = csharpCb;
            this._luaCb = luaCb;
            this._luaObj = luaObj;
        }

        /// <summary>
        /// 判断lua回调是否一样，可以用来判断防止多次加回调
        /// </summary>
        /// <param name="luaCb"></param>
        /// <param name="luaObj"></param>
        /// <returns></returns>
        public bool IsEqual(LuaFunction luaCb, LuaTable luaObj)
        {
            if (luaCb != null)
            {
                if (luaObj != null)
                {
                    return luaCb == _luaCb && luaObj == _luaObj;
                }
                return luaCb == _luaCb;
            }
            return false;
        }

        private void DoCallBack()
        {
            if (null != _csharpCb)
            {
                try
                {
                    _csharpCb();
                }
                catch (System.Exception exp)
                {
                    Logger.LogException(exp);
                }
            }
            if (null == _luaCb)
            {
                return;
            }
            try
            {
                if (null != _luaObj)
                {
                    _luaCb.Call(_luaObj);
                }
                else
                {
                    _luaCb.Call();
                }
            }
            catch (System.Exception exp)
            {
                Logger.LogException(exp);
            }
        }

        private void DoLuaCallBackWithArgs(params object[] args)
        {
            if (null == _luaCb)
            {
                return;
            }
            try
            {
                //外部调用PCall，会有置空luaCb操作，报警告：Lua stack top is 1
                _luaCb.Call(_luaObj, args);
            }
            catch (System.Exception exp)
            {
                Logger.LogException(exp);
            }
        }

        public void Reset()
        {
            _csharpCb = null;
            _luaCb = null;
            _luaObj = null;
        }
    }
}